package net.asrsmid.config;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultElement;
import org.dom4j.util.XMLErrorHandler;
import org.xml.sax.SAXException;

/**
 * public class AsRsConfigValidator<br><br>
 * The class AsRsConfigValidator is used to validate an XML config file
 * @author Chen WANG
 * @since 11 June 2011
 */
public class AsRsConfigValidator {
	private String configFile;
	//private String schemaFile;
	private SAXReader reader;
	private Document configDoc;
	//private XSSchema xsSchema;
	private XMLErrorHandler errorHandler;
	
	/**
	 * Constructs an AsRsConfigValidator object with the given XML config file name 
	 * and the given XML schema file name
	 * @param configFile the XML config file name to read and validate
	 * @param schemaFile the XML schema file with which the XML config file will be validated
	 */
	public AsRsConfigValidator(String configFile, String schemaFile) {
		this.configFile = configFile;
		//this.schemaFile = schemaFile;
		this.errorHandler = new XMLErrorHandler();
		this.reader = new SAXReader();
		
		try {
			reader.setValidation(true);
			reader.setFeature("http://xml.org/sax/features/validation", true);
			reader.setFeature("http://apache.org/xml/features/validation/schema", true);
			reader.setFeature("http://apache.org/xml/features/validation/schema-full-checking",true);
			reader.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
			reader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema-instance");
			//reader.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", schemaFile);
			reader.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", "http://www.asrsmid.net " + schemaFile);
	        reader.setErrorHandler(errorHandler);
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Validates the config file and returns a corresponding XML document object
	 * @return If the config file pass the XML schema validation, the an {@link Document}
	 * object representing the config file will be returned. Else if the config file is 
	 * not valid, null will be returned
	 */
	public Document validate() {
		// verify schema file
		/*XSOMParser parser = new XSOMParser();
		try {
			parser.parse(schemaFile);
	        xsSchema = parser.getResult().getSchema(1);
		} catch (Exception e) {
			configDoc = null;
			System.out.println("XML Schema '" + schemaFile + "' parse failed");
			e.printStackTrace();
		}*/
        
        // load xml config file
		try {
			File config = new File(configFile);
	        if (config.exists() && config.isFile()) {
	        	configDoc = reader.read(config);
	        } else {
	        	configDoc = null;
	        	System.out.println("Config file '" + configFile + "' not found");
	        }
        } catch (DocumentException e) {
        	configDoc = null;
        	System.out.println("Bad config file '" + configFile + "'");
        	e.printStackTrace();
        }

        // validation
        Element errs = errorHandler.getErrors();
        if (errs.hasContent()) {
        	@SuppressWarnings("unchecked")
        	List<DefaultElement> errList = (List<DefaultElement>) errs.content();
        	
        	List<String> errMsgList = new ArrayList<String>();
        	for (DefaultElement err : errList) {
        		if ("error".equalsIgnoreCase(err.getQName().getName()))
        			errMsgList.add("Line " + err.attributeValue("line") + " : " + err.getText());
        	}
        	
        	if (errMsgList.size() > 0) {
        		System.out.println("'" + configFile + "' conatins one or more errors :");
            	for (String msg : errMsgList) {
            		System.out.println(msg);
            	}
        	}
        }
		return configDoc;
	}
}
